﻿/**************************************************************
 *
 * 唯一标识：8211c41b-adcd-4884-8450-7f64f11bcb05
 * 命名空间：Sgr.AspNetCore.Middlewares
 * 创建时间：2023/8/18 21:46:22
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using FluentValidation;
using Microsoft.AspNetCore.Mvc;
using Sgr.AspNetCore;
using Sgr.AspNetCore.Middlewares.ExceptionHandling;
using Sgr.Exceptions;
using System;
using System.Collections;
using System.Net;
using System.Text;

namespace Sgr.ExceptionHandling
{
    /// <summary>
    /// 默认异常转换器，将异常转换为标准错误信息
    /// </summary>
    public class DefaultExceptionToErrorInfo : IExceptionToErrorInfo
    {
        private readonly IExceptionHandlingOptions _options;
        private readonly IEnumerable<IExceptionHandler> _exceptionHandlers;

        public DefaultExceptionToErrorInfo(
            IEnumerable<IExceptionHandler> exceptionHandlers,
            IExceptionHandlingOptions options)
        {
            _exceptionHandlers = exceptionHandlers ?? throw new ArgumentNullException(nameof(exceptionHandlers));
            _options = options ?? throw new ArgumentNullException(nameof(options));
        }

        /// <summary>
        /// 将异常翻译为日志消息
        /// </summary>
        /// <param name="exception">要处理的异常</param>
        /// <returns>翻译后的消息，如果没有处理器能处理此异常则返回默认消息</returns>
        public string TranslateToLog(Exception exception)
        {
            if (exception == null)
                return string.Empty;

            string message = "";
            bool isTranslated = false;

            foreach (IExceptionHandler exceptionHandler in _exceptionHandlers)
            {
                try
                {
                    if (exceptionHandler.TryTranslate(exception, ref message))
                    {
                        isTranslated = true;
                        break;
                    }
                }
                catch { /* ignored */ }
            }

            // 如果已翻译或异常消息不为空，则返回
            if (isTranslated || !string.IsNullOrEmpty(message))
                return message;

            // 如果消息为空且有内部异常，尝试处理内部异常
            if (exception.InnerException != null)
                return TranslateToLog(exception.InnerException);

            return "";
        }

        public Tuple<int, ProblemDetails> ConvertToProblemDetails(Exception exception)
        {
            Check.NotNull(exception, nameof(exception));

            // 获取HTTP状态码
            var statusCode = GetHttpStatusCode(exception);

            // 创建适当类型的 ProblemDetails
            var problemDetails = CreateProblemDetails(exception, statusCode);

            // 如果配置允许，添加详细信息
            if (_options.IncludeFullDetails)
            {
                problemDetails.Detail = exception.Message;
                AddExceptionDetails(problemDetails, exception);
            }

            return new Tuple<int, ProblemDetails>(statusCode, problemDetails);
        }

        /// <summary>
        /// 获取HTTP状态码
        /// </summary>
        protected virtual int GetHttpStatusCode(Exception exception)
        {
            return exception switch
            {
                // 4xx 客户端错误
                ArgumentException or ArgumentNullException or ArgumentOutOfRangeException
                    => StatusCodes.Status400BadRequest,
                ValidationException
                    => StatusCodes.Status400BadRequest,
                UnauthorizedAccessException
                    => StatusCodes.Status401Unauthorized,
                NotImplementedException
                    => StatusCodes.Status501NotImplemented,

                // DomainException 根据错误类型确定状态码
                DomainException domainException => domainException.ErrorType switch
                {
                    DomainErrorType.NotFound => StatusCodes.Status404NotFound,
                    DomainErrorType.Validation => StatusCodes.Status400BadRequest,
                    DomainErrorType.Conflict => StatusCodes.Status409Conflict,
                    DomainErrorType.LimitExceeded => StatusCodes.Status429TooManyRequests,
                    _ => StatusCodes.Status400BadRequest
                },

                // 业务异常通常是客户端问题
                BusinessException => StatusCodes.Status400BadRequest,

                // 默认为服务器错误
                _ => StatusCodes.Status500InternalServerError
            };
        }

        /// <summary>
        /// 创建适当类型的 ProblemDetails
        /// </summary>
        protected virtual ProblemDetails CreateProblemDetails(Exception exception, int statusCode)
        {
            ProblemDetails problemDetails = (exception is ValidationException validationException)
                ? CreateValidationProblemDetails(validationException, statusCode) : new ProblemDetails
                {
                    Status = statusCode,
                    Title = GetTitle(exception, statusCode),
                    Detail = exception.Message?.Length > 20 ? string.Concat(exception.Message[..20], "...") : exception.Message,
                    Type = GetProblemType(exception)
                };

            AddErrorCode(problemDetails, exception);

            return problemDetails;
        }

        /// <summary>
        /// 添加错误代码
        /// </summary>
        protected virtual void AddErrorCode(ProblemDetails problemDetails, Exception exception)
        {
            var errorCode = exception switch
            {
                ValidationException => "VALIDATION_ERROR",
                DomainException domainEx => !string.IsNullOrEmpty(domainEx.ErrorCode)
                    ? domainEx.ErrorCode
                    : "DOMAIN_ERROR",
                BusinessException => "BUSINESS_ERROR",
                _ => "SYSTEM_ERROR"
            };

            problemDetails.Extensions["errorCode"] = errorCode;
        }

        /// <summary>
        /// 创建验证错误的 ProblemDetails
        /// </summary>
        protected virtual ValidationProblemDetails CreateValidationProblemDetails(
            ValidationException validationException,
            int statusCode)
        {
            string title = "";
            var errors = new Dictionary<string, string[]>();

            if (validationException.Errors != null)
            {
                var errorGroups = validationException.Errors
                    .GroupBy(x => x.PropertyName)
                    .ToDictionary(
                        g => g.Key,
                        g => g.Select(x => x.ErrorMessage).ToArray()
                    );

                foreach (var error in errorGroups)
                {
                    errors[error.Key] = error.Value;

                    if (string.IsNullOrEmpty(title))
                    {
                        title = error.Value.FirstOrDefault() ?? "";
                    }
                }
            }
            var validationProblemDetails = new ValidationProblemDetails(errors)
            {
                Status = statusCode,
                Title = title,// 输入数据有误，请检查并重试
                Detail = validationException.Message?.Length > 20 ? string.Concat(validationException.Message[..20], "...") : validationException.Message,
                Type = ProblemTypes.Validation
            };

            return validationProblemDetails;
        }

        /// <summary>
        /// 获取问题类型的URI
        /// </summary>
        protected virtual string GetProblemType(Exception exception)
        {
            return exception switch
            {
                ValidationException => ProblemTypes.Validation,
                UnauthorizedAccessException => ProblemTypes.Unauthorized,
                DomainException => ProblemTypes.DomainError,
                BusinessException => ProblemTypes.BusinessError,
                NotImplementedException => ProblemTypes.NotImplemented,
                _ => ProblemTypes.InternalError
            };
        }

        /// <summary>
        /// 获取错误标题
        /// </summary>
        protected virtual string GetTitle(Exception exception, int statusCode)
        {
            return exception switch
            {
                ValidationException => "输入数据有误，请检查并重试",
                UnauthorizedAccessException => "您暂无权限访问此功能",
                NotImplementedException => "该功能正在开发中",
                DomainException => "请求处理失败，请检查输入是否正确",
                BusinessException => "操作无法完成，请确认后重试",
                _ => "系统繁忙，请稍后再试"
            };
        }

        /// <summary>
        /// 添加异常详细信息
        /// </summary>
        protected virtual void AddExceptionDetails(ProblemDetails problemDetails, Exception exception)
        {
            var details = new StringBuilder();
            details.AppendLine($"Exception Type: {exception.GetType().FullName}");

            // 添加异常数据
            if (exception.Data?.Count > 0)
            {
                details.AppendLine("Exception Data:");
                foreach (DictionaryEntry entry in exception.Data)
                {
                    details.AppendLine($"  {entry.Key}: {entry.Value}");
                }
            }

            // 添加堆栈跟踪
            if (!string.IsNullOrEmpty(exception.StackTrace))
            {
                details.AppendLine("Stack Trace:");
                details.AppendLine(exception.StackTrace);
            }

            // 添加内部异常
            if (exception.InnerException != null)
            {
                details.AppendLine("Inner Exception:");
                details.AppendLine($"  {exception.InnerException.GetType().Name}: {exception.InnerException.Message}");
            }

            problemDetails.Extensions["debugInfo"] = details.ToString();
        }
    }
}